type Pos { x: Integer, y: Integer };
type Size { w: Number, h: Number };
type Rect { x: Integer, y: Integer, w: Number, h: Number };
method Rect.pos: Pos &{x,y} => {x,y};
method Rect.size: Size &{w,h} => {w,h};

type WindowKind protected String;
const WindowKindOrdinary: WindowKind { |WindowKind| 'ordinary' };
const WindowKindDialog: WindowKind { |WindowKind| 'dialog' };
const WindowKindPopup: WindowKind { |WindowKind| 'popup' };

export function interact-with-window:
    & { kind:     WindowKind,
        title:    Computed[String],
        content:  Component,
        assets:   List[Asset],
        pos:      Maybe[Pos],
        size:     Size,
        on-close: Maybe[Async],
        modal:    Bool
        // TODO: min-size
    }      =>     Async[never]
    default {
        kind: WindowKindOrdinary,
        assets: [],
        pos: None,
        size: { w: 35, h: 25 },
        on-close: None,
        modal: No
    }
    native '__UiInteractWithWindow';

export function popup:
    & { content: & { close: Sync } => Component,
        assets:  List[Asset],
        ref:     Maybe[Rect],
        size:    Size
        // TODO: relative position (below, center, ...)
    } => Async
    default { assets: [], ref: None }
    & { content, assets, ref, size } =>
        { with-canceller &(close) =>
            { interact-with-window {
                kind: WindowKindPopup,
                title: { const 'popup' },
                content: ({ content {close} } with
                    { Event ('keydown.global.key=Escape', { EventCallback close }) }),
                assets,
                pos: (ref map &(ref) => { x: ref.x, y: (ref.y + ref.h) }),
                size,
                on-close: { Some close }
            } }
        };

export function modal-get-color:
    & { title: String, initial: Color } => Async[Maybe[Color]]
    default { initial: Black }
    native '__UiModalGetColor';

export function modal-get-line:
    & { title: String, prompt: String, initial: String } => Async[Maybe[String]]
    native '__UiModalGetLine';

export function modal-get-small-integer:
    & { title: String, prompt: String, initial: Integer,
        min: Integer, max: Integer,
        step: Number } => Async[Maybe[Integer]]
    default {
        min: Int32Min,
        max: Int32Max,
        step: 1
    }
    native '__UiModalGetSmallInteger';

export function modal-get-small-number:
    & { title: String, prompt: String, initial: Number,
        min: Number, max: Number,
        step: Number } => Async[Maybe[Number]]
    default {
        min: 0,
        max: Int32Max,
        step: 1
    }
    native '__UiModalGetSmallInteger';

export function modal-get-normal-float:
    & { title: String, prompt: String, initial: NormalFloat,
        min: NormalFloat, max: NormalFloat,
        step: NormalFloat, decimals: Number } => Async[Maybe[NormalFloat]]
    default {
        min: { !! { NormalFloat? Int32Min.Float } },
        max: { !! { NormalFloat? Int32Max.Float } },
        step: 0.25,
        decimals: 2
    }
    native '__UiModalGetNormalFloat';


